#!/bin/bash

# Shell script to pull CMON metrics from Joyent Triton
# shellcheck disable=SC2154
if [[ -n "$TRACE" ]]; then
    export PS4='[\D{%FT%TZ}] ${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
    set -o xtrace
fi

export PATH=/opt/pkg/bin:/opt/local/bin:/opt/custom/bin:$PATH

call() {
    curl --connect-timeout 10 "$insecure" "${header:--i}" -s --compressed --cert "$cert" --key "$key" "https://${1}/${2}"
    exit $?
}

do_genconfig() {
    local datacenters
    local dc_names

    if [[ -n $gz ]]; then
        printf 'Prometheus does not support discovery of CNs.\n'
        # shellcheck disable=SC2016
        printf 'Use file_sd and `cmon -g targets` instead.\n'
        exit 1
    fi

    datacenters=$(get_datacenters)
    # shellcheck disable=SC2207
    dc_names=( $(get_dcnames) )

    cat << EOF
global:
  scrape_interval:     10s
  evaluation_interval: 8s
  # scrape_timeout is set to the global default 10s

scrape_configs:
- job_name: prometheus
  scrape_interval: 5s
  static_configs:
    - targets: ['localhost:9090']

EOF

    for dc in "${dc_names[@]}"; do
        dc_url="$(json -Ma -c "this.key==\"$dc\"" value <<< "$datacenters")"
        print_prom_job "$dc" "$dc_url"
    done
}

do_keys() {
    keydir=$(get_cmonkeydir)
    mkdir -p ~/.triton/cmon/"${keydir}"
    cd ~/.triton/cmon/"${keydir}" || return
    export SDC_ACCOUNT="$user"
    triton -p "${profile}" -a "$SDC_ACCOUNT" profile cmon-certgen -y
}

do_targets() {
    local dcname
    local kind='cns'
    local objs
    dcname="$(get_dcname)"

    if [[ -z $gz ]]; then
        printf 'Prometheus supports triton_sd for containers directly.\n'
        # shellcheck disable=2016
        printf 'Use `cmon genconfig` instead.\n'
        exit 1
    fi

    # shellcheck disable=2207
    objs=( $(call "${socket:?}" "v1/${gz}discover" | json -Ha "$kind" | json -a -o jsony-0) )
    # shellcheck disable=2207
    targets=(
        $(for o in "${objs[@]}"; do
            read -r -a u <<< "$(json -ga server_uuid server_hostname <<< "$o")"
            printf '{"targets":'
            printf '["%s.%s"],' "${u[0]}" "$socket"
            printf '"labels":'
            printf '{"server_uuid":"%s","hostname":"%s","datacenter":"%s"' "${u[0]}" "${u[1]}" "$dcname"
            printf '}}\n'
        done)
    )

    t=$(join , "${targets[@]}")

    printf '[%s]' "$t" | json
}


get_cmonkeydir () {
    local url
    profile_j=$(triton -p "$profile" profile get -j)
    url=$(json url <<< "$profile_j" | sed -E 's/^https?//g' | tr -d :/ | tr '.' _)
    echo "${user}@${url}"
}

get_datacenters() {
    triton -p "$profile" datacenters -j
}

get_dcname() {
    cut -d '.' -f 2 <<< "$socket"
}

get_dcnames() {
    local datacenters
    datacenters="$(get_datacenters)"
    json -Ma key <<< "$datacenters"
}

get_profile() {
    triton -p "$profile" profile get -j
}

function join {
    local IFS="$1"; shift; echo "$*";
}

parse_cmon_url () {
    # shellcheck disable=2207
    parts=( $(tr -d '/' <<< "$1" | tr ':' ' ') )
    echo "${parts[@]}"
}

print_prom_job () {
    local dc="$1"
    local url="$2"
    # shellcheck disable=2207
    local cmon=($(parse_cmon_url "$(triton -a "$user" -p "$profile" -U "$url" services -j | json cmon)"))
    local scheme="${cmon[0]}"
    local endpoint="${cmon[1]}"
    # Not used
    #local port="${cmon[2]}"

    cat << EOF
- job_name: ${user}_${dc}
  scheme: ${scheme}
  tls_config:
    cert_file: ${cert}
    key_file: ${key}
    ${config_insecure}
  triton_sd_configs:
    - account: ${user}
      dns_suffix: ${endpoint}
      endpoint: ${endpoint}
      version: 1
      tls_config:
        cert_file: ${cert}
        key_file: ${key}
        ${config_insecure}
  relabel_configs:
    - source_labels: [__meta_triton_machine_alias]
      target_label: alias
    - source_labels: [__meta_triton_machine_id]
      target_label: zonename
    - source_labels: [__param_datacenter_name]
      target_label: datacenter_name
      replacement: ${dc}
    - source_labels: [__param_account]
      target_label: account_name
      replacement: ${user}

EOF

}

strip_proto() {
    #sed 's#https://##' <<< "$1"
    echo "${1/*:\/\/}"
}

usage () {
    printf '%s [ -g ] [ -p profile ] [ -c certficate ] [ -k key ] targets\n' "${0##*/}"
    printf '%s [ -g ] [ -p profile ] [ -c certficate ] [ -k key ] [ -G groups ] discover\n' "${0##*/}"
    printf '%s [ -p profile ] [ -c certficate ] [ -k key ] metrics vm_uuid|server_uuid\n' "${0##*/}"
    printf '%s [ -p profile ] -u username keysetup\n' "${0##*/}"
    printf '%s [ -p profile ] -u username genconfig\n' "${0##*/}"
    printf '\n    -g\tDiscover Compute Nodes (gz metrics)\n'
    exit "$1"
}

while getopts "e:c:k:p:u:G:ghiH" options; do
    case $options in
        H) header=' ';;
        c) cert="${OPTARG}";;
        e) socket="${OPTARG}";;
        g) gz="gz/";;
        G) groups="?groups=${OPTARG}" ;;
        i)
            insecure="-k";
            config_insecure="insecure_skip_verify: true";
            ;;
        k) key="${OPTARG}";;
        p) profile="${OPTARG}";;
        u) user="${OPTARG}";;
        h) usage 0;;
        *) usage 1;;
    esac
done

shift $(( OPTIND - 1 ))

if [[ -z $user ]] || [[ -z $socket ]]; then
    # Default profile
    profile_json=$(get_profile)
fi

if [[ -n $profile ]]; then
    profile=$(json name <<< "$profile_json")
fi

if [[ -z $user ]]; then
    user=$(json account <<< "$profile_json")
fi

if [[ -z $socket ]]; then
    socket=$(triton -p "$profile" services -j | json cmon)
fi

socket=$(strip_proto "$socket")
action="$1"
inst="$2"

if [[ -z $cert ]] || [[ -z $key ]]; then
    keydir=$(get_cmonkeydir)
fi

# Use certs generated by triton profile cmon-certgen
if [[ -z $cert ]]; then
    cert=~/.triton/cmon/"${keydir}"/cmon-${user}-cert.pem
fi
if [[ -z $key ]]; then
    key=~/.triton/cmon/"${keydir}"/cmon-${user}-key.pem
fi

if [[ -z $socket ]]; then
    printf 'Profile "%s" does not list a cmon endpoint\n' "$profile"
    exit 1
fi

case $action in
    disco|discover)
        call "${socket:?}" "v1/${gz}discover${groups}"
        ;;
    metrics)
        call "${inst:?}.${socket}" metrics
        ;;
    certgen|keysetup)
        do_keys
        ;;
    targets)
        do_targets
        ;;
    genconfig)
        if [[ -z $user ]]; then
            printf 'user is required for config generation\n'
            usage 1
        fi
        do_genconfig;
        ;;
    *)
        printf 'Not implemented\n'
        ;;
esac